package com.jule.teenpatti.game.network.protocol.reqs;

import JoloProtobuf.GameSvr.JoloGame;
import com.google.common.primitives.Ints;
import com.jule.core.common.log.LoggerUtils;
import com.jule.teenpatti.base.enums.ErrorCodeEnum;
import com.jule.teenpatti.base.enums.GameConst;
import com.jule.teenpatti.game.dao.bean.CommonConfigModel;
import com.jule.teenpatti.game.model.PlayerInfo;
import com.jule.teenpatti.game.model.eenum.PlayTypeEnum;
import com.jule.teenpatti.game.model.eenum.PlayerStateEnum;
import com.jule.teenpatti.game.network.protocol.ClientReq;
import com.jule.teenpatti.game.network.protocol.acks.JoloGame_ApplySeeCardAck_50006;
import com.jule.teenpatti.game.play.AbstractTable;
import com.jule.teenpatti.game.play.TableUtil;
import com.jule.teenpatti.game.service.TableService;
import com.jule.teenpatti.game.service.holder.CardOfTableHolder;
import com.jule.teenpatti.game.utils.log.TableLogUtil;
import com.jule.teenpatti.game.vavle.notice.NoticeBroadcastMessages;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;

/**
 * 接口：申请看自己的牌
 */
public class JoloGame_ApplySeeCardReq_50006 extends ClientReq {
    private long time;
    private final static Logger logger = LoggerFactory.getLogger(JoloGame_ApplySeeCardReq_50006.class);

    public JoloGame_ApplySeeCardReq_50006(int functionId) {
        super(functionId);
    }

    private JoloGame.JoloGame_ApplySeeCardReq req;

    @Override
    public void readPayLoadImpl(ByteBuf buf) throws Exception {
        time = System.currentTimeMillis();
        byte[] blob = new byte[buf.readableBytes()];
        buf.readBytes(blob);
        req = JoloGame.JoloGame_ApplySeeCardReq.parseFrom(blob);
        this.setTable(TableService.getInstance().getTable(header.gameId + "", req.getRoomId(), req.getTableId()));
    }

    @Override
    public void processImpl() {
        logger.debug("收到消息：申请看牌-> " + functionId + ", reqNum-> " + header.reqNum + ", req->" + req.toString());
        String userId = req.getUserId();
        String roomId = req.getRoomId();
        String tableId = req.getTableId();
        String gameOrderId = req.getGameOrderId();

        //获得桌子配置信息
        JoloGame.JoloGame_ApplySeeCardAck.Builder ack = JoloGame.JoloGame_ApplySeeCardAck.newBuilder();
        ack.setUserId(userId);
        ack.setRoomId(roomId);
        ack.setTableId(tableId);
        ack.setGameOrderId(gameOrderId);

        AbstractTable table = getTable();
        try {
            PlayerInfo player = table.getPlayer(userId);
            if (null == player) {
                logger.info("can't found player info, playerId->" + userId);
                ack.setResult(-1).setResultMsg(ErrorCodeEnum.GAME_50050_2.getCode());

                ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));
                return;
            }

            if (player.getState().getValue() == PlayerStateEnum.spectator.getValue()
                    || player.getState().getValue() == PlayerStateEnum.fold.getValue()
                    || player.getState().getValue() == PlayerStateEnum.settle.getValue()
                    || player.getState().getValue() == PlayerStateEnum.see_card.getValue()) {
                logger.info("player state invalid,can't see card. playerId->" + userId + ", state->" + player.getState());
                ack.setResult(-2).setResultMsg(ErrorCodeEnum.GAME_50006_1.getCode());
                ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));
                return;
            }

            if (player.getSeatNum() <= 0) {
                logger.info("player have no seat,can't see card. playerId->" + userId);
                ack.setResult(-3).setResultMsg(ErrorCodeEnum.GAME_50014_1.getCode());
                ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));
                return;
            }

            //由于孤注一掷比牌的原因 会出现玩家状态值为2(看牌) 但实际本人没看的情况
//            if (player.getIsBlind() != 1) {
//                logger.error("player already see card. player->" + player.getIsBlind());
//                ack.setResult(-4).setResultMsg(ErrorCodeEnum.GAME_50006_2.getCode());
//                ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));
//                return;
//            }

            //如果是blind模式则不允许看牌
            if (table.currPlayType() == PlayTypeEnum.blind.getGameId()) {
                logger.info("current playtype not allow see card");
                ack.setResult(-5).setResultMsg(ErrorCodeEnum.GAME_50006_2.getCode());
                ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));
                return;
            }

            //根据玩法的不同获取不同数量的手牌
            int[] arrHandCards;
            //由于孤注一掷比牌的原因 会出现玩家状态值为2(看牌) 但实际本人没看的情况
            if(player.getIsBlind() == 1) {
                arrHandCards = table.getHandCard(userId);
            }else {
                arrHandCards = player.getHandCards();
            }

            player.setHandCards(arrHandCards); //玩家看牌后则为手牌赋值
            ack.addAllHandCards(Ints.asList(arrHandCards));
            //修改玩家状态（已看牌）
            player.setIsBlind(2);
            table.setSeeCardNum(table.getSeeCardNum() + 1);
            if (table.getSeeCardNum() > 1) { //看牌人数至少两人才能sideshow
                CommonConfigModel commonConfig = table.getCommonConfig();
                if (commonConfig.isChooseSideShowUser()) { //指定玩家比牌
                    for (PlayerInfo playerInfo : table.getInGamePlayers().values()) {
                        if (playerInfo.getIsBlind() != 1) {
                            playerInfo.setIsCanSideShow(1);
                        }
                    }
                } else { //只能和上家比
                    for (Integer in : table.getInGamePlayers().keySet()) {
                        PlayerInfo targetPlayer = TableUtil.getPreBetPlayer(table, in);
                        PlayerInfo playerInfo = table.getInGamePlayers().get(in);
                        if (targetPlayer.getIsBlind() != 1 && playerInfo.getIsBlind() != 1) {
                            playerInfo.setIsCanSideShow(1);
                        }
                    }
                }
            }
            //todo 有时间再优化
            if (table.getInGamePlayers().size() == 2 && table.getSeeCardNum() == 2) { //如果本局游戏只剩两人则可以show
                for (PlayerInfo playerInfo : table.getInGamePlayers().values()) {
                    playerInfo.setIsCanShow(1);
                }
            }

            //返回手牌数据
            ack.setResult(1);
            ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));

            logger.debug("玩家已看牌，userId->{}, nickName->{},reqNum->{}", player.getPlayerId(), player.getNickName(), header.reqNum);

            table.setLastActionTime(System.currentTimeMillis());

            TableLogUtil.seenCard(functionId, "seenCard", userId, table.getPlayType() + "", table.getRoomId(),
                    table.getTableId(), table.getCurrGameOrderId(), Arrays.toString(player.getHandCards()));
            //广播事件：玩家已看牌
            try {
                NoticeBroadcastMessages.playerSeeCard(table, player, table.getInGamePlayersByPlayerId().get(table.getCurrActionPlayerId()));
            } catch (Exception ex) {
                logger.error("SendNotice ERROR：", ex);
            }
            long timeMillis = System.currentTimeMillis() - time;
            if (timeMillis > GameConst.COST_TIME) {
                LoggerUtils.performance.info("ApplySeeCardReq_50006,cost time:{},req:{}", timeMillis, req.toString());
            }
        } catch (Exception ex) {
            logger.error("系统异常：userId->" + userId + ", gameOrderId->" + gameOrderId + ", message->" + ex);
            ack.setResult(-1);
            ack.setResultMsg(ErrorCodeEnum.GAME_50002_2.getCode());
            ctx.writeAndFlush(new JoloGame_ApplySeeCardAck_50006(ack.build(), header));
        } finally {
            logger.debug("SeeCard ACK info: " + ack.toString());
            logger.debug("SeeCard ACK bytes length: " + ack.build().toByteArray().length);
            if (null != table) {
                logger.debug("All Player info: " + System.getProperty("line.separator") + TableUtil.toStringAllPlayers(table));
                logger.debug("InGame Player info: " + System.getProperty("line.separator") + TableUtil.toStringInGamePlayers(table));
            }
            logger.debug("SeeCard over. Table state: " + table.getTableStateEnum());

            long useTimes = System.currentTimeMillis() - time;
            if(useTimes > 500) {
                logger.error("ApplySeeCard。 耗时->{} 毫秒, reqNum->{}", useTimes, header.reqNum); //TODO:临时增加
            }
        }
    }
}
